#include <events/common_log.h>
#include <time.h>
#include <stdint.h>
#include "sf_string.h"
#include "sf_date_time.h"

#define INVALID_ZONE  1111
/*
1) UTC

整个地球分为二十四时区，每个时区都有自己的本地时间。在国际无线电通信场合，为了统一起见，使用一个统一的时间，称为通用协调时(UTC, Universal Time Coordinated)。

(2) GMT

格林威治标准时间 (Greenwich Mean Time)指位于英国伦敦郊区的皇家格林尼治天文台的标准时间，因为本初子午线被定义在通过那里的经线。(UTC与GMT时间基本相同，本文中不做区分)

(3) CST

中国标准时间 (China Standard Time)

(4) DST

夏令时(Daylight Saving Time) 指在夏天太阳升起的比较早时，将时钟拨快一小时，以提早日光的使用。（中国不使用）

GMT + 8 = UTC + 8 = CST

(5) PDT
太平洋夏季时间（Pacific Daylight Time）。太平洋时间的标准时间从协调世界时减去8小时(UTC 8)。在夏令时的基础上，它的时间是基于太阳的时间，它是根据格林威治天文台第105号子午线的太阳时间而定的。
相对应的是PST（Pacific Standard Time ）。 夏时制结束后就是PST。


localtime:
    将时间数值变换成本地时间,考虑到本地时区和夏令时标志

*/
enum {
    UTC_BASE_YEAR = 1970,
    DAY_PER_YEAR = 365,
    MONTH_PER_YEAR = 12,
    SECS_PER_DAY = 86400,
    MSECS_PER_DAY = 86400000,
    SECS_PER_HOUR = 3600,
    MSECS_PER_HOUR = 3600000,
    SECS_PER_MIN = 60,
    MSECS_PER_MIN = 60000,
    TIME_T_MAX = 2145916799,  // int maximum 2037-12-31T23:59:59 UTC
    JULIAN_DAY_FOR_EPOCH = 2440588 // result of julianDayFromDate(1970, 1, 1)
};

#define qMin(a, b) (((a) > (b)) ? (b) : (a))

static int _g_time_zone = INVALID_ZONE;

static int repeatCount(const SFString &s, int i)
{
    char c = s.at(i);
    int j  = i + 1;
    while (j < (int)s.size() && s.at(j) == c)
    {
        ++j;
    }
    return j - i;
}
static bool timeFormatContainsAP(const SFString &format)
{
    int i = 0;
    while (i < (int)format.size())
    {
        char ch = format.at(i);

        if (ch == 'a' || ch == 'A')
        {
            return true;
        }

        ++i;
    }
    return false;
}

#define longLongToString(num, a, b, width, c) \
        numToString(num, width)
static std::string numToString(int num, int width = 1)
{
    std::string tmp;
    char str[16];
    int  len;

    len = sprintf(str, "%d", num);
    // GEN_Printf(LOG_DEBUG, "len = %d, width = %d", len, width);
    while (len < width)
    {
        tmp.append(1, '0');
        len++;
    }
    // GEN_Printf(LOG_DEBUG, "len = %d, str = %s, %s", len, str, tmp.c_str());
    tmp.append(str);

    return tmp;
}

/**
 * @brief toString
 * @param sec [in] 相当于系统事件的time
 * @param msec [in] 毫秒数
 * @return 返回符合格式的字符串
 */
static SFString _toString(int64_t sec, int msec, const SFString &format)
{
    std::string result;
    time_t t_t = sec;
    struct tm tp;
    struct tm * t = ::localtime_r(&t_t, &tp);

    int year   = t->tm_year + 1900;
    int month  = t->tm_mon + 1;
    int day    = t->tm_mday;
    int hour   = t->tm_hour;
    int minute = t->tm_min;
    int second = t->tm_sec;

//    GEN_Printf(LOG_DEBUG, "%ld, %d, fmt: %s", sec, msec, format.c_str());
//    GEN_Printf(LOG_DEBUG, "%d-%d-%d %d:%d:%d", year, month, day, hour, minute, second);

//    std::string mon = numToString(month, 2);
//    GEN_Printf(LOG_DEBUG, "size = %ld", mon.size());
//    GEN_Printf(LOG_DEBUG, "%d, %s", month, numToString(month, 2).c_str());

    for (int i = 0; i < (int)format.size(); )
    {
        char c     = format.at(i);
        int repeat = repeatCount(format, i);
        bool used  = false;
        switch (c) {
        case 'y':
            used = true;
            if (repeat >= 4)
            {
                repeat = 4;
            } else if (repeat >= 2)
            {
                repeat = 2;
            }

            switch (repeat) {
            case 4: {
                const int yr = year;
                const int len = (yr < 0) ? 5 : 4;
                result.append(longLongToString(yr, -1, 10, len, QLocaleData::ZeroPadded));
                break;
            }
            case 2:
                result.append(longLongToString(year % 100, -1, 10, 2,
                                                       QLocaleData::ZeroPadded));
                break;
            default:
                repeat = 1;
                result.append(c, 1);
                break;
            }
            break;

        case 'M':
            used = true;
            repeat = qMin(repeat, 4);
            switch (repeat) {
            case 1:
                result.append(numToString(month));
                break;
            case 2:
            default:
                result.append(longLongToString(month, -1, 10, 2, QLocaleData::ZeroPadded));
            }
            break;

        case 'd':
            used = true;
            repeat = qMin(repeat, 4);
            switch (repeat) {
            case 1:
                result.append(numToString(day));
                break;
            case 2:
            default:
                result.append(longLongToString(day, -1, 10, 2, QLocaleData::ZeroPadded));
                break;
            }
            break;
        case 'h': {
            used = true;
            repeat = qMin(repeat, 2);
            if (timeFormatContainsAP(format))
            {
                if (hour > 12)
                {
                    hour -= 12;
                } else if (hour == 0)
                {
                    hour = 12;
                }
            }

            switch (repeat) {
            case 1:
                result.append(numToString(hour));
                break;
            case 2:
                result.append(longLongToString(hour, -1, 10, 2, QLocaleData::ZeroPadded));
                break;
            }
            break;
        }
        case 'H':
            used = true;
            repeat = qMin(repeat, 2);
            switch (repeat) {
            case 1:
                result.append(numToString(hour));
                break;
            case 2:
                result.append(longLongToString(hour, -1, 10, 2, QLocaleData::ZeroPadded));
                break;
            }
            break;

        case 'm':
            used = true;
            repeat = qMin(repeat, 2);
            switch (repeat) {
            case 1:
                result.append(numToString(minute));
                break;
            case 2:
                result.append(longLongToString(minute, -1, 10, 2, QLocaleData::ZeroPadded));
                break;
            }
            break;

        case 's':
            used = true;
            repeat = qMin(repeat, 2);
            switch (repeat) {
            case 1:
                result.append(numToString(second));
                break;
            case 2:
                result.append(longLongToString(second, -1, 10, 2, QLocaleData::ZeroPadded));
                break;
            }
            break;

        case 'a':
            used = true;
            if (i + 1 < (int)format.length() && format.at(i + 1) == 'p')
            {
                repeat = 2;
            } else
            {
                repeat = 1;
            }
            result.append(hour < 12 ? "am" : "pm");
            break;

        case 'A':
            used = true;
            if (i + 1 < (int)format.length() && format.at(i + 1) == 'P')
            {
                repeat = 2;
            } else
            {
                repeat = 1;
            }
            result.append(hour < 12 ? "AM" : "PM");
            break;

        case 'z':
            used = true;
            if (repeat >= 3) {
                repeat = 3;
            } else {
                repeat = 1;
            }

            // note: the millisecond component is treated like the decimal part of the seconds
            // so ms == 2 is always printed as "002", but ms == 200 can be either "2" or "200"
            result.append(longLongToString(msec, -1, 10, 3, QLocaleData::ZeroPadded));
            if (repeat == 1)
            {
                result.resize(result.size() - 2);
            }

            break;

        default:
            // GEN_Printf(LOG_WARN, "unkown template fmt: %c = %d", c, repeat);
            break;
        }

        if (!used)
        {
            result.append(std::string(repeat, c));
        }

        // GEN_Printf(LOG_DEBUG, "%c = %d, %d = %s", c, repeat, result.size(), result.c_str());

        i += repeat;
    }

    return result;
}

#if 0
namespace {
static inline int64_t floordiv(int64_t a, int b)
{
    return (a - (a < 0 ? b - 1 : 0)) / b;
}

static inline int floordiv(int a, int b)
{
    return (a - (a < 0 ? b - 1 : 0)) / b;
}
static inline int64_t julianDayFromDate(int year, int month, int day)
{
    // Adjust for no year 0
    if (year < 0)
        ++year;

/*
 * Math from The Calendar FAQ at http://www.tondering.dk/claus/cal/julperiod.php
 * This formula is correct for all julian days, when using mathematical integer
 * division (round to negative infinity), not c++11 integer division (round to    zero)
 */
    int     a = floordiv(14 - month, 12);
    int64_t y = (int64_t)year + 4800 - a;
    int     m = month + 12 * a - 3;
    //GEN_Printf(LOG_DEBUG, "a=%d, y: %ld, m: %d", a, y, m);
    return day + floordiv(153 * m + 2, 5) + 365 * y + floordiv(y, 4) - floordiv(y, 100) + floordiv(y, 400) - 32045;
}

struct ParsedDate
{
    int year, month, day;
};
// 朱利安日期
static inline ParsedDate getDateFromJulianDay(int64_t julianDay)
{
/*
 * Math from The Calendar FAQ at http://www.tondering.dk/claus/cal/julperiod.php
 * This formula is correct for all julian days, when using mathematical integer
 * division (round to negative infinity), not c++11 integer division (round to zero)
 */
    int64_t a = julianDay + 32044;
    int64_t b = floordiv(4 * a + 3, 146097);
    int     c = a - floordiv(146097 * b, 4);

    int    d = floordiv(4 * c + 3, 1461);
    int    e = c - floordiv(1461 * d, 4);
    int    m = floordiv(5 * e + 2, 153);

    int    day = e - floordiv(153 * m + 2, 5) + 1;
    int    month = m + 3 - 12 * floordiv(m, 10);
    int    year = 100 * b + d - 4800 + floordiv(m, 10);

    // Adjust for no year 0
    if (year <= 0)
        --year ;

    const ParsedDate result = { year, month, day };
    return result;
}
}
#endif

namespace {
/* 自定义的时间结构体 */
typedef struct
{
    uint16_t nYear;
    uint8_t nMonth;
    uint8_t nDay;
    uint8_t nHour;
    uint8_t nMin;
    uint8_t nSec;
    uint8_t DayIndex; /* 0 = Sunday */
} mytime_struct;

const uint8_t g_day_per_mon[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

/**
 * @brief is_leap_year
 *  判断是否是闰年
 * @param year 需要判断的年份数
 * @return 闰年返回1，否则返回0
 */
uint8_t is_leap_year(uint16_t year)
{
#if 1
    if ((year % 400) == 0)
    {
        return 1;
    } else if ((year % 100) == 0)
    {
        return 0;
    } else if ((year % 4) == 0)
    {
        return 1;
    } else
    {
        return 0;
    }
#else
    return __isleap(year) ? 1 : 0;
#endif
}
/**
 * @brief last_day_of_mon
 *      得到每个月有多少天
 * @param month 需要得到天数的月份数
 * @param year 该月所对应的年份数
 * @return  该月有多少天
 */
uint8_t last_day_of_mon(uint8_t month, uint16_t year)
{
    if ((month == 0) || (month > 12))
    {
        return g_day_per_mon[1] + is_leap_year(year);
    }

    if (month != 2)
    {
        return g_day_per_mon[month - 1];
    } else
    {
        return g_day_per_mon[1] + is_leap_year(year);
    }
}
#if 0
/**
 * @brief dt_dayindex
 *  根据给定的日期得到对应的星期
 * @param year 给定的年份
 * @param month 给定的月份
 * @param day 给定的天数
 * @return  对应的星期数，0 - 星期天 ... 6 - 星期六
 */
uint8_t dt_dayindex(uint16_t year, uint8_t month, uint8_t day)
{
    char century_code, year_code, month_code, day_code;
    int week = 0;

    century_code = year_code = month_code = day_code = 0;

    if (month == 1 || month == 2)
    {
        century_code = (year - 1) / 100;
        year_code = (year - 1) % 100;
        month_code = month + 12;
        day_code = day;
    } else
    {
        century_code = year / 100;
        year_code = year % 100;
        month_code = month;
        day_code = day;
    }

    /* 根据蔡勒公式计算星期 */
    week = year_code + year_code / 4 + century_code / 4 - 2 * century_code + 26 * ( month_code + 1 ) / 10 + day_code - 1;
    week = week > 0 ? (week % 7) : ((week % 7) + 7);

    return week;
}

/**
 * @brief utc_sec_2_mytime
 *  根据UTC时间戳得到对应的日期
 * @param utc_sec 给定的UTC时间戳
 * @param result 计算出的结果
 * @param daylightSaving 是否是夏令时
 */
void utc_sec_2_mytime(unsigned int utc_sec, mytime_struct *result, bool daylightSaving)
{
    /*----------------------------------------------------------------*/
    /* Local Variables                                                */
    /*----------------------------------------------------------------*/
    int sec, day;
    unsigned short y;
    unsigned char m;
    unsigned short d;
    //unsigned char dst;

    /*----------------------------------------------------------------*/
    /* Code Body                                                      */
    /*----------------------------------------------------------------*/

    if (daylightSaving)
    {
        utc_sec += SECS_PER_HOUR;
    }

    /* hour, min, sec */
    /* hour */
    sec = utc_sec % SECS_PER_DAY;
    result->nHour = sec / SECS_PER_HOUR;

    /* min */
    sec %= SECS_PER_HOUR;
    result->nMin = sec / SECS_PER_MIN;

    /* sec */
    result->nSec = sec % SECS_PER_MIN;

    /* year, month, day */
    /* year */
    /* year */
    day = utc_sec / SECS_PER_DAY;
    for (y = UTC_BASE_YEAR; day > 0; y++)
    {
        d = (DAY_PER_YEAR + is_leap_year(y));
        if (day >= d)
        {
            day -= d;
        } else
        {
            break;
        }
    }

    result->nYear = y;

    for (m = 1; m < MONTH_PER_YEAR; m++)
    {
        d = last_day_of_mon(m, y);
        if (day >= d)
        {
            day -= d;
        } else
        {
            break;
        }
    }

    result->nMonth = m;
    result->nDay = (unsigned char) (day + 1);
    /* 根据给定的日期得到对应的星期 */
    result->DayIndex = dt_dayindex(result->nYear, result->nMonth, result->nDay);
}
unsigned int mytime_2_utc_sec(mytime_struct *currTime, bool daylightSaving)
{
    /*----------------------------------------------------------------*/
    /* Local Variables                                                */
    /*----------------------------------------------------------------*/
    unsigned short i;
    unsigned int no_of_days = 0;
    int utc_time;
    unsigned char dst;

    /*----------------------------------------------------------------*/
    /* Code Body                                                      */
    /*----------------------------------------------------------------*/
    if (currTime->nYear < UTC_BASE_YEAR) {
        return 0;
    }

    /* year */
    for (i = UTC_BASE_YEAR; i < currTime->nYear; i++)
    {
        no_of_days += (DAY_PER_YEAR + is_leap_year(i));
    }

    /* month */
    for (i = 1; i < currTime->nMonth; i++)
    {
        no_of_days += last_day_of_mon((unsigned char) i, currTime->nYear);
    }

    /* day */
    no_of_days += (currTime->nDay - 1);

    /* sec */
    utc_time = (unsigned int) no_of_days * SECS_PER_DAY + (unsigned int) (currTime->nHour * SECS_PER_HOUR +
                                                                currTime->nMin * SECS_PER_MIN + currTime->nSec);

    if (dst && daylightSaving)
    {
        utc_time -= SECS_PER_HOUR;
    }

    return utc_time;
}
#endif
}
SFDate::SFDate(int64_t jd)
    : m_jd(jd/SECS_PER_DAY)
{}

SFDate::SFDate(int year, int month, int day)
{
    SF_ASSERT(year > 0 && month > 0 && month < 13 && day > 0 && day < 32);

//    int64_t jd = julianDayFromDate(year, month, day) - julianDayFromDate(1970, 1, 1) ;
//    GEN_Printf(LOG_DEBUG, "jd: %ld", jd);

    int64_t no_of_days = 0;
    if (UTC_BASE_YEAR <= year)
    {
        // year
        for (int i = UTC_BASE_YEAR; i < year; i++)
        {
            no_of_days += (DAY_PER_YEAR + is_leap_year(i));
        }
        // month
        for (int i = 1; i < month; i++)
        {
            no_of_days += last_day_of_mon((uint8_t) i, year);
        }
        // day
        no_of_days += day - 1;

        m_jd = no_of_days;
    } else
    {
        for (int i = year+1; i < UTC_BASE_YEAR; ++i)
        {
            no_of_days += (DAY_PER_YEAR + is_leap_year(i));
        }
        for (int i = month+1; i < 13; i++)
        {
            no_of_days += last_day_of_mon((uint8_t) i, year);
        }

        no_of_days += last_day_of_mon((uint8_t) month, year) - (day - 1);

        m_jd = -no_of_days;
    }
    // GEN_Printf(LOG_DEBUG, "m_jd: %ld", m_jd);
}

void SFDate::setTime_t(int64_t dt)
{
    m_jd =  dt / SECS_PER_DAY;
}

int64_t SFDate::toTime_t() const
{
    return m_jd * SECS_PER_DAY;
}

int SFDate::toWeek() const
{
    time_t cur = m_jd * SECS_PER_DAY;
    struct tm tp;
    struct tm *res = ::localtime_r(&cur, &tp);

    return res->tm_wday+1;
}

int SFDate::toMonthDay() const
{
    time_t cur = m_jd * SECS_PER_DAY;
    struct tm tp;
    struct tm *res = ::localtime_r(&cur, &tp);

    return res->tm_mday;
}

int SFDate::toMonth() const
{
    time_t cur = m_jd * SECS_PER_DAY;
    struct tm tp;
    struct tm *res = ::localtime_r(&cur, &tp);

    return res->tm_mon+1;
}

int SFDate::toYear() const
{
    //return getDateFromJulianDay(m_jd).year;
    time_t cur = m_jd * SECS_PER_DAY;
    struct tm tp;
    struct tm *res = ::localtime_r(&cur, &tp);

    return res->tm_year + 1900;
}

SFString SFDate::toString(const SFString &format) const
{
    return _toString(m_jd * SECS_PER_DAY, 0, format);
}

SFDate SFDate::fromString(const SFString &/*date*/)
{
    return SFDate();
}

SFDate SFDate::currentDate()
{
    struct timeval  tv;
    struct timezone tz;

    gettimeofday(&tv, &tz);

//    struct tm tp;
//    struct tm *res = ::localtime_r(&tv.tv_sec, &tp);
//    int64_t dt =  julianDayFromDate(res->tm_year+1900, res->tm_mon+1, res->tm_mday);
//    GEN_Printf(LOG_DEBUG, "date: %ld -- %ld", dt, tv.tv_sec / SECS_PER_DAY);

    // 记录天数
    return SFDate(tv.tv_sec);
    // return SFDate(dt);
}

int SFDate::getMonthDay(int mouth)
{
    if (mouth < 0) mouth = 11;
    else if (mouth > 11) mouth = 0;
    return g_day_per_mon[mouth];
}

SFTime::SFTime(int h, int m, int s, int ms)
{
    SF_ASSERT((uint)h < 24 && (uint)m < 60 && (uint)s < 60 && (uint)ms < 1000);

    if (INVALID_ZONE == _g_time_zone)
    {
        SFDateTime::resetTimeZone();
    }
    // 加上这个偏移值，否则得出的结果有偏差
    // 需要考虑时区的问题
    h += _g_time_zone;

    m_ds = (h*SECS_PER_HOUR + m*SECS_PER_MIN + s)*1000 + ms;
}

SFString SFTime::toString(const SFString &format) const
{
    return _toString(m_ds / 1000, m_ds % 1000, format);
}

/**
 * @brief SFTime::msecsTo
 * @param t
 * @return 返回从此时到t的毫秒数。如果t早于此时，返回的毫秒数为负。
    因为SFTime度量的是一天之内的时间，一天有86400秒，所以结果总是在-86400000到86400000毫秒之间。
    如果第一次返回0
 */
int SFTime::msecsTo(const SFTime &t) const
{
    return m_ds - t.m_ds;
}
int SFTime::secsTo(const SFTime &t) const
{
    return (m_ds - t.m_ds)/1000;
}

SFTime SFTime::currentTime()
{
    struct timeval  tv;
    struct timezone tz;

    gettimeofday(&tv, &tz);

    return SFTime((tv.tv_sec % SECS_PER_DAY) * 1000 + tv.tv_usec / 1000);
}

SFTime SFTime::currentTime2Sec()
{
    struct timeval  tv;
    struct timezone tz;

    gettimeofday(&tv, &tz);

    return SFTime((tv.tv_sec % SECS_PER_DAY) * 1000);
}

SFTime SFTime::currentTime2Minute()
{
    struct timeval  tv;
    struct timezone tz;

    gettimeofday(&tv, &tz);

    int minute = ((tv.tv_sec % SECS_PER_DAY) / SECS_PER_MIN);

    return SFTime(minute * MSECS_PER_MIN);
}

void SFTime::setSecond(int sec, int msec)
{
    int tmp = m_ds / MSECS_PER_MIN; //(60 * 1000)
    m_ds = tmp * (sec * 1000 + msec);
}

void SFTime::setMSecond(int val)
{
    int tmp = m_ds / 1000;
    m_ds = tmp * val;
}

SFDateTime::SFDateTime(const SFTime &tm)
    : mTime(tm.m_ds)
{}

SFDateTime::SFDateTime(const SFDate &date)
    : mTime(date.m_jd * MSECS_PER_DAY)
{}

SFDateTime::SFDateTime(const SFDate &date, const SFTime &tm)
    : mTime(date.m_jd * MSECS_PER_DAY + tm.m_ds)
{
}

SFDateTime SFDateTime::addDays(int day) const
{
    int64_t tmp = day;
    int64_t cur = mTime;
    int64_t val = cur + (tmp * MSECS_PER_DAY);
    return SFDateTime(val > 0 ? val : 0);
}

SFDate SFDateTime::date()
{
    return SFDate(mTime / 1000);
}

SFTime SFDateTime::time()
{
    return SFTime (mTime % MSECS_PER_DAY);
}

void SFDateTime::setTime_t(int64_t dt)
{
    mTime = dt * 1000;
}

int64_t SFDateTime::toTime_t() const
{
    return mTime / 1000;
}

SFDateTime SFDateTime::toLocalTime()
{
    return SFDateTime(*this);
}

SFDateTime SFDateTime::toUTC()
{
    return SFDateTime(*this);
}

SFString SFDateTime::toString(const SFString &format) const
{
    return _toString(mTime / 1000, mTime % 1000, format);
}

SFDateTime SFDateTime::currentDateTimeUtc()
{
    struct timeval  tv;
    struct timezone tz;

    gettimeofday(&tv, &tz);

    return SFDateTime(tv.tv_sec * 1000LL + tv.tv_usec / 1000LL);
}

SFDateTime SFDateTime::currentDateTime()
{
    struct timeval  tv;
    struct timezone tz = {0, 0};

    gettimeofday(&tv, &tz);

    int64_t cur = tv.tv_sec * 1000LL + tv.tv_usec / 1000LL;

    //GEN_Printf(LOG_DEBUG, "gettimeofday: %ld.%ld, cur: %llu", tv.tv_sec, tv.tv_usec, (unsigned long long)cur);
    //GEN_Printf(LOG_DEBUG, "zoneinfo: minuteswest=%d, dsttime=%d", tz.tz_minuteswest, tz.tz_dsttime);

    return SFDateTime(cur);
}

SFDateTime SFDateTime::fromTime_t(int64_t val)
{
    return SFDateTime(val * 1000LL);
}

SFDateTime SFDateTime::fromTime_tByTZ(int64_t val)
{
    if (INVALID_ZONE == _g_time_zone)
    {
        SFDateTime::resetTimeZone();
    }

    // 需要加上时区
    return SFDateTime(val * 1000LL + _g_time_zone * MSECS_PER_HOUR);
}

void SFDateTime::resetTimeZone()
{
#if 0 //def PLATFORM_ARM
    tzset();

    _g_time_zone = __timezone / SECS_PER_HOUR;
    GEN_Printf(LOG_DEBUG, "%s,%s,%ld", __tzname[0], __tzname[1], __timezone);
    GEN_Printf(LOG_DEBUG, "Current timezone: %d", _g_time_zone);
#endif
}

int SFDateTime::getSysTimeZone()
{
    if (INVALID_ZONE == _g_time_zone)
    {
        SFDateTime::resetTimeZone();
    }

    return _g_time_zone;
}

